#!/usr/bin/python

#-------------------------------------------------------------------------------
# Name:        main
# Purpose:     Launch and manage threads and events.
#
# Author:      Donald L Talbert , www.bwhgaming.com
#
# Created:     20/09/2012
# Copyright:   (c) Donald L Talbert 2012
# Licence:     MIT
#-------------------------------------------------------------------------------

# Import builtin modules
import logging
import threading
import time

# Import my modules
import serverautocontrol
import checkplatform
import backup
import updateserver
import loadconfig
import autosetup



class ControlThreads(object):
    """
    This class launches and maintains all the threads and their events handling
    communication between threads to make sure operations run in a thread-safe
    way.
    """
    def __init__(self):
        """
        Sets up the event signals when the class is called. Details below...

        """
        # Main Control Thread Events
        self.eRunServerThread = threading.Event() # Launches the Server Control Thread.
        self.eRunUpdateThread = threading.Event() # Launches the Update Thread.
        self.eRunBackupThread = threading.Event() # Launches the Backup Thread.

        # Sub Control Thread Events
        self.eServerThreadStop = threading.Event()  # Stops all running servers.
        self.eServerThreadRestarts = threading.Event() # Disable automatic thread restarting.

        # ##
        self.lc = loadconfig.LoadConfig()
        self.numServers = self.lc.numServers

        self.timeBetweenBackups = self.lc.timeBetweenBackups
        self.readyToBackup = False
        self.currentlyBackingUp = False

        self.timeBetweenUpdates = self.lc.timeBetweenUpdates
        self.readyToUpdate = False
        self.currentlyUpdating = False

        self.firstRun = self.lc.firstRun

        # Check if this is the first time running this program and configure.
        if self.firstRun == "True":
            logging.info("Configuring for first time use...")
            autosetup.main()
        else:
            pass


    def UpdateThread(self):
        """
        Checks if a server update is needed. If needed, it stops all current
        servers and blocks them from respawning, applies the updates, then
        it restarts the servers. This must be called with the eRunUpdateThread
        event.

        """
        while True:
            if self.readyToUpdate == False:
                logging.debug('Update Check Thread Waiting.')
                time.sleep(int(self.timeBetweenUpdates))
                #time.sleep(60) #DEBUG
                self.readyToUpdate = True
                logging.info("Checking for Updates...")
                continue

            elif self.currentlyBackingUp == True:
                time.sleep(1)
                continue

            elif self.readyToUpdate == True:
                self.readyToUpdate = False
                self.currentlyUpdating = True

            self.eRunUpdateThread.wait() # Wait for signal to start update

            a = updateserver.UpdateServer()
            updated = a.Main() # Update and report back a bool if its up to date

            if updated == True: # Do nothing
            #if updated == False: # Debug
                self.currentlyUpdating = False
                time.sleep(1)
                continue

            elif updated == False:
            #elif updated == True: # Debug
                self.eRunServerThread.clear() # Stop the run server thread
                self.eServerThreadStop.set()  # Stop all servers
                self.eServerThreadRestarts.clear() # Stop servers from restarting

                time.sleep(5)

                self.eServerThreadStop.clear() # Signal to not stop future servers
                self.eServerThreadRestarts.set() # Signal to resume the servers run loop
                self.eRunServerThread.set() # Signal to the main server thread to start the servers back up.
                self.currentlyUpdating = False
                continue

            #break ##
        #return ##

    def BackupThread(self):
        """
        Backups the server to the specified directory in the config file.
        It waits for eRunBackupThread signal then backups up the current
        server directory to the backup directory then clears its signal/event.

        """
        while True:
            if self.readyToBackup == False:
                logging.debug('Backup Thread Waiting.')
                time.sleep(int(self.timeBetweenBackups))
                #time.sleep(120) #DEBUG
                self.readyToBackup = True
                logging.info("Backing Up Server...")
                continue

            elif self.currentlyUpdating == True:
                time.sleep(1)
                continue

            elif self.readyToBackup == True:
                self.readyToBackup = False
                self.currentlyBackingUp = True

            self.eRunBackupThread.wait() # wait for the signal to start the backup.
            a = backup.Backup()
            a.Backup() # backups the server.
            self.currentlyBackingUp = False
            continue

            #break ##
        #return ##


    def ServerThread(self): # This needs to have a loop and launch servers via threads.
        """
        Loops and launches other threads for each server specified in the configuration.

        """
        while True:
            self.eRunServerThread.wait() # wait for the signal to start launching the servers.
            a = serverautocontrol

            x = 1
            while x <= self.numServers:
                print x
                thread = threading.Thread(name="Server-" + str(x), target=a.ServerAutoControl(x, self.eServerThreadStop, self.eServerThreadRestarts).Launch)
                thread.setDaemon(True)
                thread.start()
                print x
                x = x + 1

            logging.info("Servers online...")

            self.eRunServerThread.clear() # clears the signal/event and loops back.


    def MainThread(self): #while an event is true. Manage coordinating backups, updates, stops, and launches.
        """
        This launches all the control threads and sets inital events to
        start the program.

        """

        # Starting threads but not executing yet.
        serverThread = threading.Thread(name = "ServerThread", target = self.ServerThread)
        serverThread.setDaemon(True)
        serverThread.start()

        updateThread = threading.Thread(name = "UpdateThread", target = self.UpdateThread)
        updateThread.setDaemon(True)
        updateThread.start()

        backupThread = threading.Thread(name = "BackupThread", target = self.BackupThread)
        backupThread.setDaemon(True)
        backupThread.start()


        # Allowing threads to run
        self.eRunServerThread.set()
        self.eServerThreadRestarts.set()
        self.eRunUpdateThread.set()
        self.eRunBackupThread.set()

        while True:
            time.sleep(1)


def Main():
    """
    The launcher.
    """
    a = ControlThreads()
    a.MainThread()


if __name__ == "__main__":
    logging.basicConfig(level=logging.DEBUG, format='[%(levelname)s] %(asctime)s - %(threadName)-10s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
    Main()
